[v1.4] 脚本资源更新逻辑重构 ( updateResource 相关代码 ) 与 并发控制优化 (资源更新同步机制) 重构#1193
Conversation
|
UI 部份另行处理 |
| await this.scriptCodeDAO.save({ | ||
| uuid: script.uuid, | ||
| code: param.code, | ||
| }); | ||
| logger.info("install success"); | ||
|
|
||
| // Cache更新 & 下载资源 | ||
| await Promise.all([ | ||
| compiledResourceUpdatePromise, | ||
| this.resourceService.updateResourceByType(script, "require"), | ||
| this.resourceService.updateResourceByType(script, "require-css"), | ||
| this.resourceService.updateResourceByType(script, "resource"), | ||
| this.resourceService.updateResourceByTypes(script, ["require", "require-css", "resource"]), | ||
| ]); | ||
| // 如果资源不完整,还是要接受安装吗??? | ||
|
|
||
| // 广播一下 | ||
| // Runtime 會負責更新 CompiledResource | ||
| this.publishInstallScript(script, { update, upsertBy }); | ||
|
|
||
| return { update }; | ||
| }) | ||
| .catch((e: any) => { | ||
| logger.error("install error", Logger.E(e)); | ||
| throw e; | ||
| }); |
There was a problem hiding this comment.
@CodFrm scriptDAO 先 save 了显示成功。 如果资源下载失败,忽略掉是故意的吗?
是的话我就不改这做法
否则就改成下载不了不安装不更新
There was a problem hiding this comment.
那我这个 PR 先不处理这个,先维持
| const updateTime = oldResources?.updatetime; | ||
| // 资源最后更新是24小时内则不更新 | ||
| // 这里是假设 resources 都是 static. 使用者应该加 ?d=xxxx 之类的方式提示SC要更新资源 | ||
| if (updateTime && updateTime > Date.now() - 86400_000) return; |
There was a problem hiding this comment.
@CodFrm 原代码有这个 updateTime 检查操作。但脚本更新可以是每6小时做一次。如果脚本更新了但资源不更新,好像有点奇怪
There was a problem hiding this comment.
之前考虑过不做这个检查,感觉也可以,资源加载下来就不再失效,除非修改url
|
@CodFrm 修改好了。你可以给AI看 |
|
@CodFrm 这个在 1.4 版加入吧。不然又要拖多一两个月了。 |
明白,我尽快,看看有没有精力来处理 |
|
本地看了一轮,结论:暂不建议合并。这次 PR 的资源下载链路能跑到,但有两个确定问题会影响核心目标。 阻塞问题1.
|
| // 滑动窗口语义: | ||
| // - fetch 超时 (timeouted=true) → 提前归还槽位,下一个请求可以启动 | ||
| // - fetch 完成/失败 (settled=true) → 归还槽位(若 timeout 已归还则为 no-op) | ||
| // 原 fetch 在超时后仍继续运行,响应到达时照常处理(不会被取消) | ||
| const { result, err } = await withTimeoutNotify( | ||
| fetch(url), | ||
| FETCH_SLOT_SLIDE_TIMEOUT_MS, | ||
| ({ settled, timeouted }) => { | ||
| if (timeouted || settled) { | ||
| releaseSlotOnce(); | ||
| } | ||
| } | ||
| ); |
| if (u.url && !u.url.startsWith("file:///") && oldResources?.contentType) { | ||
| const updateTime = oldResources.updatetime; | ||
| // 资源最后更新是24小时内则不更新 | ||
| // 这里是假设 resources 都是 static. 使用者应该加 ?d=xxxx 之类的方式提示SC要更新资源 | ||
| if (updateTime && updateTime > Date.now() - RESOURCE_CACHE_TTL_MS) return; | ||
| } |
| it.concurrent("超时后回调被调用,promise 完成后再次调用", async () => { | ||
| vi.useFakeTimers(); | ||
| let resolvePromise: (v: string) => void; | ||
| const promise = new Promise<string>((r) => { | ||
| resolvePromise = r; |
| it.concurrent("超时后 promise 失败,回调也被调用两次", async () => { | ||
| vi.useFakeTimers(); | ||
| let rejectPromise: (e: Error) => void; | ||
| const promise = new Promise<string>((_, reject) => { | ||
| rejectPromise = reject; |
| it.concurrent("double release 输出警告", () => { | ||
| const sem = new Semaphore(1); | ||
| const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); | ||
|
|
||
| sem.release(); | ||
| expect(warnSpy).toHaveBeenCalledWith("Semaphore double release detected"); | ||
|
|
||
| warnSpy.mockRestore(); | ||
| }); |
updateResourceByTypes 在 24 小时 TTL 命中时直接 return,不会把当前脚本 uuid 写入 resource.link。多个脚本复用同一 URL 时,删除其中一个脚本会把仍被其它脚本使用的资源一并删除。 TTL 命中时也补登记 link(只更新 link 字段,避开 getResourceModel 对 SRI 校验失败时改写 content 的副作用)。
- gm-api.spec.ts: scriptscat#1477 迁移到本地 mock server 时漏改 unwrap 测试,仍引用已删除的 TARGET_URL 导致 ReferenceError。改用 cspOrigin,并把 unwrap_e2e_test token 接入 patchTargetMatchCode - concurrency-control.test.ts: 操作全局计时器/console 的 3 个用例从 it.concurrent 改回顺序 it,避免并发互相干扰偶现失败
为 v1.4.0-beta.3 → beta.4 的核心改动补充 Playwright E2E(复用现有两阶段 userScripts fixture,并新增本地 mock server + host-resolver 域名映射,全程不依赖外网): - resource-update: @require/@resource 注入与读取、24h TTL 同 URL 去重、 拉取失败优雅降级、多 require 并发全部加载 (#1193) - gm-xhr-site-access: 跨域 @connect 放行、x-sc-request-marker 经 DNR 剥离、 非 @connect 域名拒绝 (#1477, mv3_utils) - background-script: @background 脚本经 Chrome offscreen 执行并具备 DOM 环境 (#1457) - user-config-yaml: 含 __proto__ 的恶意 @userconfig 被拒、原型链未污染 (#1494) - backup-zip: 备份导出/导入 zip 往返(JSZipp generateAsync/loadAsync)(#1479) - server-fixtures: 共享 fixture + mock server
为 v1.4.0-beta.3 → beta.4 的核心改动补充 Playwright E2E(复用现有两阶段 userScripts fixture,并新增本地 mock server + host-resolver 域名映射,全程不依赖外网): - resource-update: @require/@resource 注入与读取、24h TTL 同 URL 去重、拉取失败优雅降级、多 require 并发全部加载 (#1193) - gm-xhr-site-access: 跨域 @connect 放行、x-sc-request-marker 经 DNR 剥离、非 @connect 域名拒绝 (#1477, mv3_utils) - background-script: @background 脚本经 Chrome offscreen 执行,具备 DOM 环境,并通过脚本内 GM 值读写闭环 + mock server probe 做稳定断言 (#1457) - user-config-yaml: 含 __proto__ 的恶意 @userconfig 被拒、原型链未污染 (#1494) - backup-zip: 备份导出/导入 zip 往返(JSZipp generateAsync/loadAsync)(#1479) - e2e waits: 移除固定 sleep/忙等,改为条件等待;并升级 workflow action runtime 版本 - server-fixtures: 共享 fixture + mock server
为 v1.4.0-beta.3 → beta.4 的核心改动补充 Playwright E2E(复用现有两阶段 userScripts fixture,并新增本地 mock server + host-resolver 域名映射,全程不依赖外网): - resource-update: @require/@resource 注入与读取、24h TTL 同 URL 去重、拉取失败优雅降级、多 require 并发全部加载 (#1193) - gm-xhr-site-access: 跨域 @connect 放行、x-sc-request-marker 经 DNR 剥离、非 @connect 域名拒绝 (#1477, mv3_utils) - background-script: @background 脚本经 Chrome offscreen 执行,具备 DOM 环境,并通过脚本内 GM 值读写闭环 + mock server probe 做稳定断言 (#1457) - user-config-yaml: 含 __proto__ 的恶意 @userconfig 被拒、原型链未污染 (#1494) - backup-zip: 备份导出/导入 zip 往返(JSZipp generateAsync/loadAsync)(#1479) - e2e waits: 移除固定 sleep/忙等,改为条件等待;并升级 workflow action runtime 版本 - server-fixtures: 共享 fixture + mock server
1. 变更概述 (Overview)
本 PR 对脚本资源的更新逻辑进行了深度重构,核心目标是提升在复杂场景下资源更新的稳定性与效率。
通过引入并发控制机制、统一资源获取接口并修复多项历史遗留的逻辑问题,确保了系统在大规模资源更新及高频请求环境下的可靠性,有效预防了 Service Worker 可能出现的崩溃或请求堆积问题。
2. 主要改动 (Key Changes)
核心逻辑重构
updateResourceByType扩展为updateResourceByTypes,实现了多类型资源的并行处理能力。loadByUrlcreateResourceByUrlFetch),使代码意图更明确。file:///)的路径识别与更新逻辑,增强了兼容性。并发控制与性能优化
concurrency-control.ts模块,为资源下载(fetch)过程增加并行上限限制。系统健壮性提升 (Service Worker)
runtime.ts和script.ts中关于资源状态同步的 BUG,确保前后端数据一致。synchronize.ts逻辑,剔除冗余的数据库读写操作,降低 I/O 开销。工程质量与测试
resource、utils及concurrency-control的单元测试,确保重构逻辑的零退化。3. 技术细节 (Technical Details)
concurrency-control模块,动态限制资源下载的最大并发数,平衡更新速度与系统负载。getScriptResourceValue标准化接口,统一了资源值的读取路径。我都不知道要怎么说明了
反正就是有问题的部份改了
有些觉得奇怪的,我没有改,只加了 comment
变更内容 Changes
截图 Screenshots